﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using Microsoft.Practices.Unity;
using Wyn.PMS.Common.Utils;
using Wyn.PMS.Entity.Entities;
using Wyn.PMS.Entity.IDataAccess;

namespace Wyn.PMS.Test.Cache
{
    public class FixLedgerTotal
    {
        private static readonly IUnityContainer container = UnityContainerService.GetContainer();

        public void Total(string hotelId , DateTime date, IList<Account> accounts)
        {
            INaLedgerTotalRepository totalRepository = container.Resolve<INaLedgerTotalRepository>();

            ILedgerRepository ledgerRepository = container.Resolve<ILedgerRepository>();

            DateTime yesterBizDay = date.Date.AddDays(-1);

            DateTime todayBizDay = date.Date;

            Expression<Func<NaLedgerTotal, bool>> exp = n => n.HotelID == hotelId && n.BizDay == yesterBizDay;

            var yesterdayTotals = totalRepository.BatchFind(hotelId, exp);

            var allLeger = ledgerRepository.BatchFind(hotelId, r => r.IsValid);

            IList<Ledger> parentLedgers = allLeger.Where(r => r.LedgerParentCode == LedgerCode.根代码).ToList();

            IList<Ledger> subLedgers = allLeger.Where(r => r.LedgerParentCode != LedgerCode.根代码).ToList();
            
            IList<NaLedgerTotal> ledgerTotals = new List<NaLedgerTotal>();

            foreach (var ledger in subLedgers)
            {
                var yesterTotal = yesterdayTotals.FirstOrDefault(t => t.LedgerCode == ledger.LedgerCode);

                var ledgerAccounts = accounts.Where(a => a.LedgerCode == ledger.LedgerCode);

                var total = BuildLedgerTotal(yesterTotal, ledgerAccounts, ledger, todayBizDay, hotelId);

                ledgerTotals.Add(total);
            }

            foreach (var ledger in parentLedgers)
            {
                var parentTotals = ledgerTotals.Where(t => t.ParentCode == ledger.LedgerCode);

                var total = BuildParentTotal(parentTotals, hotelId, todayBizDay, ledger);

                ledgerTotals.Add(total);
            }
            FixAnalysis fixAnalysis = new FixAnalysis();

            var checkinTyps = fixAnalysis.GetCheckInTypes();

            foreach (var type in checkinTyps)
            {
                var yesterTotal = yesterdayTotals.FirstOrDefault(t => t.LedgerCode == type.Key);

                var checkInAccounts = accounts.Where(a => a.CheckInType == type.Key && a.LedgerCode == LedgerCode.标准房租);

                var total = BuildCheckInTypeTotal(yesterTotal, checkInAccounts, type.Key, type.Value, todayBizDay, hotelId);

                ledgerTotals.Add(total);
            }

            var oldTotals = totalRepository.BatchFind(hotelId,o=>o.HotelID==hotelId&&o.BizDay==todayBizDay);
            
            IList<NaLedgerTotal> updates = new List<NaLedgerTotal>();

            IList<NaLedgerTotal> adds = new List<NaLedgerTotal>();

            foreach (var total in ledgerTotals)
            {
                if (oldTotals.Any(o => o.LedgerCode == total.LedgerCode))
                {
                    updates.Add(total);
                }
                else
                {
                    adds.Add(total);
                }
            }

            try
            {
                //adds= adds.Where(a => a.ParentCode == LedgerCode.入住类型之父).ToList();

                //updates = updates.Where(a => a.ParentCode == LedgerCode.入住类型之父).ToList();

                totalRepository.BatchInsert(hotelId,adds);

                totalRepository.BatchUpdate(hotelId, updates);
            }
            catch (Exception ex)
            {
                Wyn.PMS.Common.SecurityControl.OperateLog.ErrorLog(ex.Message,ex);
            }

        }

        private NaLedgerTotal BuildCheckInTypeTotal(NaLedgerTotal yesterTotal, IEnumerable<Account> checkInAccounts, string checkInType, string checkInName, DateTime todayBizDay, string hotelId)
        {
            var total = new NaLedgerTotal();

            total.BizDay = todayBizDay;

            total.HotelID = hotelId;

            total.LedgerCode = checkInType;

            total.LedgerName = checkInName;

            total.LedgerType = AccountType.D;

            total.ParentCode = LedgerCode.入住类型之父;

            if (checkInAccounts != null && checkInAccounts.Any())
            {
                total.TodayOccur = checkInAccounts.Sum(l => l.Balance);

                total.TodayRecede = Math.Abs(checkInAccounts.Where(l => l.Balance < 0).Sum(l => l.Balance));

                total.TodayActualMoney = checkInAccounts.Sum(l => l.ActualMoney);

                total.ItemCount = checkInAccounts.Count();
            }
            
            if (yesterTotal != null && yesterTotal.BizDay.Month == todayBizDay.Month)
            {
                total.MonthBalance = yesterTotal.MonthBalance + total.TodayOccur;
                total.MonthActualMoney = yesterTotal.MonthActualMoney + total.TodayActualMoney;
                total.TotalBanlance = yesterTotal.TotalBanlance + total.TodayOccur;
            }
            else
            {
                total.MonthBalance = total.TodayOccur;
                total.MonthActualMoney = total.TodayActualMoney;
                total.TotalBanlance = total.TodayOccur;
            }
            
            if (yesterTotal != null && yesterTotal.BizDay.Year == todayBizDay.Year)
            {
                total.YearBalance = yesterTotal.YearBalance + total.TodayOccur;
                total.YearActualMoney = yesterTotal.YearActualMoney + total.TodayActualMoney;
            }
            else
            {
                total.YearBalance = total.TodayOccur;
                total.YearActualMoney = total.TodayActualMoney;
            }

            return total;
        }

        private NaLedgerTotal BuildLedgerTotal(NaLedgerTotal yesterTotal, IEnumerable<Account> ledgerAccounts, Ledger ledger, DateTime todayBizDay, string hotelId)
        {
            var total = new NaLedgerTotal();

            if (ledgerAccounts!=null && ledgerAccounts.Any())
            {
                total.TodayOccur = ledgerAccounts.Sum(l => l.Balance);

                total.TodayActualMoney = ledgerAccounts.Sum(l => l.ActualMoney);

                total.TodayRecede = Math.Abs(ledgerAccounts.Where(l => l.Balance < 0).Sum(l => l.Balance));

                total.ItemCount = ledgerAccounts.Count();
            }
            
            if (yesterTotal != null && yesterTotal.BizDay.Month == todayBizDay.Month)
            {
                total.MonthBalance = yesterTotal.MonthBalance + total.TodayOccur;
                total.MonthActualMoney = yesterTotal.MonthActualMoney + total.TodayActualMoney;
                total.TotalBanlance = yesterTotal.TotalBanlance + total.TodayOccur;
            }
            else
            {
                total.MonthBalance = total.TodayOccur;
                total.MonthActualMoney = total.TodayActualMoney;
                total.TotalBanlance = total.TodayOccur;
            }
            
            if (yesterTotal != null && yesterTotal.BizDay.Year == todayBizDay.Year)
            {
                total.YearBalance = yesterTotal.YearBalance + total.TodayOccur;
                total.YearActualMoney = yesterTotal.YearActualMoney + total.TodayActualMoney;
            }
            else
            {
                total.YearBalance = total.TodayOccur;
                total.YearActualMoney = total.TodayActualMoney;
            }

            total.BizDay = todayBizDay;

            total.HotelID = hotelId;

            total.LedgerCode = ledger.LedgerCode;

            total.LedgerName = ledger.LedgerName;

            total.LedgerType = ledger.LedgerType;

            total.ParentCode = ledger.LedgerParentCode;

            return total;
        }

        private NaLedgerTotal BuildParentTotal(IEnumerable<NaLedgerTotal> ledgerTotals,string hotelId,DateTime bizDay,Ledger ledger)
        {
            var total = new NaLedgerTotal();

            total.BizDay = bizDay;

            total.HotelID = hotelId;

            total.LedgerCode = ledger.LedgerCode;

            total.LedgerName = ledger.LedgerName;

            total.LedgerType = ledger.LedgerType;

            total.ParentCode = ledger.LedgerParentCode;

            if (ledgerTotals.Any())
            {
                total.ItemCount = ledgerTotals.Sum(t=>t.ItemCount);

                total.TodayOccur = ledgerTotals.Sum(t => t.TodayOccur);

                total.TodayRecede = ledgerTotals.Sum(t => t.TodayRecede);

                total.MonthBalance = ledgerTotals.Sum(t => t.MonthBalance);

                total.YearBalance = ledgerTotals.Sum(t => t.YearBalance);

                total.TodayActualMoney = ledgerTotals.Sum(t => t.TodayActualMoney);

                total.MonthActualMoney = ledgerTotals.Sum(t => t.MonthActualMoney);

                total.YearActualMoney = ledgerTotals.Sum(t => t.YearActualMoney);
            }

            return total;
        }
    
    }
}
